package lc.animation;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.junit.Test;

import com.jme.math.Quaternion;
import com.jme.math.Vector3f;

public class AnimationTest {

	String name = "hello";
	float duration = 1.5f;
	float[] timestamps = new float[] { 1, 2 };
	Keyframe[] keyframes = new Keyframe[] { null, null };
	Keyframe[] tangentsIn = new Keyframe[] { null, null };
	Keyframe[] tangentsOut = new Keyframe[] { null, null };

	Vector3f translation0 = new Vector3f(1, 2, 3);
	Quaternion rotation0 = new Quaternion(0.1f, 0.2f, 0.4f, 0.8f);
	Vector3f scale0 = new Vector3f(0.5f, 1.0f, 1.5f);
	Vector3f translation1 = new Vector3f(0, 0, 0);
	Quaternion rotation1 = new Quaternion(0, 0, 0, 1);
	Vector3f scale1 = new Vector3f(1, 1, 1);

	Vector3f tangent1 = new Vector3f(0.25f, 0.5f, 0.75f);
	Quaternion tangentQ1 = new Quaternion (0.1f, 0, 0, 0.2f);
	Vector3f tangent2 = new Vector3f(-0.25f, -0.5f, -0.75f);
	Quaternion tangentQ2 = new Quaternion (-0.1f, 0, 0, -0.2f);

	public AnimationTest() {
		keyframes[0] = new Keyframe(translation1, rotation1, scale1);
		keyframes[1] = new Keyframe(translation0, rotation0, scale0);
		tangentsIn[0] = new Keyframe(tangent1, tangentQ1, tangent1);
		tangentsIn[1] = new Keyframe(tangent2, tangentQ2, tangent2);
		tangentsOut[0] = new Keyframe(tangent2, tangentQ2, tangent2);
		tangentsOut[1] = new Keyframe(tangent1, tangentQ1, tangent1);
	}

	@Test
	public void testAnimation() {
		Animation a = new Animation();
		assertEquals(a.getName(), null);
		assertNotNull(a.getChildren());
	}

	void assertTimestampsEqual(float[] a, float[] b) {
		assertEquals(a.length, b.length);
		for (int i = 0, n = a.length; i != n; ++i) {
			assertEquals(a[i], b[i]);
		}
	}

	void assertKeyframesEqual(Keyframe[] a, Keyframe[] b) {
		assertEquals(a.length, b.length);
		for (int i = 0, n = a.length; i != n; ++i) {
			assertEquals(a[i], b[i]);
		}
	}

	public void verifySome(Animation a) {
		assertEquals(a.getName(), name);
		assertEquals(a.getDuration(), duration);
		assertTimestampsEqual(a.getTimestamps(), timestamps);
		assertKeyframesEqual(a.getSamples(), keyframes);
	}

	public void verifyAll(Animation a) {
		verifySome(a);
		assertKeyframesEqual(a.getTangentsIn(), tangentsIn);
		assertKeyframesEqual(a.getTangentsOut(), tangentsOut);
	}

	@Test
	public void testAnimation2() {
		Animation a = new Animation(name, duration, timestamps, keyframes, null, null);
		verifySome(a);
		assertNull(a.getTangentsIn());
		assertNull(a.getTangentsOut());
	}

	@Test
	public void testAnimation3() {
		Animation a = new Animation(name, duration, timestamps, keyframes, tangentsIn, tangentsOut);
		verifyAll(a);
	}

	@Test
	public void testAnimation4() {
		Animation a = new Animation();
		Animation b = new Animation();
		a.getChildren().add(b);
		assertEquals(a.getChildren().get(0), b);
	}

	ByteArrayOutputStream baos;

	public void doWrite() throws IOException {
		Animation a = new Animation(name, duration, timestamps, keyframes, tangentsIn, tangentsOut);
		Animation b = new Animation("", 0, null, null, null, null);
		a.getChildren().add(b);
		baos = new ByteArrayOutputStream();
		ObjectOutputStream oo = new ObjectOutputStream(baos);
		oo.writeObject(a);
		oo.close();
	}

	@Test
	public void testWriteExternal() throws IOException {
		doWrite();
		byte[] tba = baos.toByteArray();
		assert(tba.length > 100 && tba.length < 1000);
		System.out.print("Marshalled length is " + tba.length + "\n");
	}

	@Test
	public void testReadExternal() throws IOException, ClassNotFoundException {
		if (baos == null)
			doWrite();
		byte[] tba = baos.toByteArray();
		ByteArrayInputStream bais = new ByteArrayInputStream(tba);
		ObjectInputStream ois = new ObjectInputStream(bais);
		Animation a = (Animation)ois.readObject();
		verifyAll(a);
		assertNotNull(a.getChildren().get(0));
		assertEquals(a.getChildren().size(), 1);
	}
}
